"""
Python interface to KnowledgeTree REST API
"""

import new
import logging
from urllib import urlencode
from urllib2 import urlopen
from xml.dom import minidom

version = '0.1.1'

KNOWN_METHODS = (
    'copy_folder',
    'create_document_shortcut',
    'create_folder',
    'create_folder_shortcut',
    'delete_folder',
    'get_folder_contents',
    'get_folder_detail',
    'get_folder_detail_by_name',
    'get_folder_shortcuts',
    'logout',
    'move_folder',
    'rename_folder',
)

class KnowledgeTreeException(Exception):
    pass

class KnowledgeTree(object):
    def __init__(self, url, username, password, session_id=None):
        self.url = url
        self.username = username
        self.password = password
        self.session_id = session_id

    def login(self):
        self.session_id = self.submit('login', username=self.username, password=self.password)
        logging.debug('Session id set to %s' % self.session_id)

    def submit(self, method, **kwargs):
        """
        Send a "method" request to KnowledgeTree with the given keyword
            arguments.

        Return a dictionary of parsed xml.

        Raise a KnowledgeTreeException if KnowledgeTree reports an error.
        """
        if not method == 'login':
            if self.session_id is None:
                self.login()
            kwargs['session_id'] = self.session_id
        kwargs['method'] = method
        logging.debug(str(kwargs))
        url = '%s?%s' % (self.url, urlencode(kwargs))
        logging.debug('Submitting %s' % url)
        dom = minidom.parse(urlopen(url))
        logging.debug('Received: %s' % dom.toprettyxml())
        return parse(dom)

    def makedirs(self, path):
        dirs = path.split('/')
        parent_dirs = []

        last_id = 1
        while dirs:
            dir = dirs.pop(0)
            parent_dirs.append(dir)
            try:
                info = self.get_folder_detail_by_name(
                    folder_name='/'.join(parent_dirs))
            except KnowledgeTreeException:
                info = self.create_folder(folder_id=last_id, folder_name=dir)
            last_id = info['id']

# Add a bunch of very similar functions for convenience.  Using exec as python
# keeps referencing the first method if done otherwise.
method_template = """
def %(method_name)s(self, **kwargs):
    return self.submit('%(method_name)s', **kwargs)
setattr(KnowledgeTree, '%(method_name)s', %(method_name)s)
"""
for name in KNOWN_METHODS:
    exec(method_template % {'method_name': name})


def parse(dom):
    """
    Processes whole xml response from KnowledgeTree.

    Return a dictionary.
    """
    status = dom.getElementsByTagName('status_code')[0].childNodes[0].data
    if not status == '0':
        message = dom.getElementsByTagName('message')[0].childNodes[0].data
        raise KnowledgeTreeException, message
    results = dom.getElementsByTagName('results')

    if not results:
        return None

    return parse_results(results[0])

def parse_results(dom):
    """
    Processes <results> nodes.

    Bypasses KnowledgeTree bugs, like <results> in <results> in copy_folder.
    """
    data = {}
    for node in dom.childNodes:
        if node.nodeType == node.TEXT_NODE:
            return node.data
        if node.tagName in ('status_code', 'message'):
            continue
        if node.tagName == 'results':
            return parse_results(node)
        if node.tagName == 'items':
            data[node.tagName] = parse_items(node)
        else:
            if node.childNodes:
                data[node.tagName] = node.childNodes[0].data
            else:
                data[node.tagName] = None
    logging.debug('Returning data: %s' % data)
    return data

def parse_items(dom):
    """
    Processes <items> nodes.

    Is capable of recursion, even though KnowledgeTree hasn't really implemented
        the feature correctly.
    """
    items = []
    for item in dom.childNodes:
        data = {}
        for node in item.childNodes:
            if node.tagName == 'items':
                data[node.tagName] = parse_items(node)
            else:
                data[node.tagName] = node.childNodes[0].data
        items.append(data)
    return items


def main():
    import sys
    from optparse import OptionParser

    logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)

    parser = OptionParser()
    parser.add_option('-u', '--username', dest='username')
    parser.add_option('-p', '--password', dest='password')
    (options, args) = parser.parse_args()
    if not options.username:
        options.username = raw_input('Username: ')
    if not options.password:
        from getpass import getpass
        options.password = getpass()

    for url in args:
        kt = KnowledgeTree(
            url,
            options.username,
            options.password,
        )
        test_root = kt.create_folder(folder_id=1, folder_name='Testing')
        one = kt.create_folder(folder_id=test_root['id'], folder_name='one')
        two = kt.create_folder(folder_id=test_root['id'], folder_name='two')
        three = kt.create_folder(folder_id=test_root['id'], folder_name='three')
        test_info = kt.get_folder_detail_by_name(folder_name='Testing/two')
        kt.create_folder_shortcut(source_folder_id=one['id'],
            target_folder_id=three['id'])
        kt.get_folder_shortcuts(folder_id=three['id'])
        copy_info = kt.copy_folder(source_id=one['id'], target_id=two['id'], reason='why')
        kt.move_folder(source_id=copy_info['id'], target_id=one['id'], reason='why')
        kt.rename_folder(folder_id=copy_info['id'], newname='four', reason='why')
        kt.delete_folder(folder_id=test_root['id'], reason='testing')
        kt.logout()

if __name__ == '__main__':
    main()
